//! # 重试机制模块
//!
//! 提供统一的重试策略和执行器

use async_trait::async_trait;
use serde::{Deserialize, Serialize};
use std::time::Duration;
use crate::ResilienceResult;

/// 重试策略接口
#[async_trait]
pub trait RetryStrategy: Send + Sync {
    /// 计算重试延迟
    fn calculate_delay(&self, attempt: u32) -> Duration;
    
    /// 是否应该重试
    fn should_retry(&self, attempt: u32, error: &(dyn std::error::Error + Send + Sync)) -> bool;
    
    /// 获取最大重试次数
    fn max_attempts(&self) -> u32;
    
    /// 重置重试状态
    fn reset(&mut self);
}

/// 退避策略
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum BackoffStrategy {
    /// 固定延迟
    Fixed { delay: Duration },
    /// 线性增长
    Linear { initial_delay: Duration, increment: Duration },
    /// 指数退避
    Exponential { 
        initial_delay: Duration, 
        max_delay: Duration, 
        multiplier: f64 
    },
    /// 自定义策略
    Custom { name: String },
}

/// 重试配置
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct RetryConfig {
    /// 最大重试次数
    pub max_attempts: u32,
    /// 退避策略
    pub backoff_strategy: BackoffStrategy,
    /// 重试条件
    pub retry_conditions: Vec<RetryCondition>,
    /// 重试预算（百分比）
    pub budget_percent: f64,
    /// 是否启用抖动
    pub jitter_enabled: bool,
    /// 超时时间
    pub timeout: Option<Duration>,
}

/// 重试条件
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub enum RetryCondition {
    /// 网络错误
    NetworkError,
    /// 超时
    Timeout,
    /// HTTP状态码
    HttpStatus(u16),
    /// HTTP状态码范围
    HttpStatusRange(u16, u16),
    /// 自定义条件
    Custom(String),
}

/// 重试结果
#[derive(Debug)]
pub enum RetryResult<T> {
    /// 成功
    Success(T),
    /// 重试中
    Retrying { attempt: u32, delay: Duration },
    /// 最终失败
    Failed { attempts: u32, last_error: String },
}

/// 重试执行器
pub struct RetryExecutor {
    config: RetryConfig,
}

impl RetryExecutor {
    pub fn new(config: RetryConfig) -> Self {
        Self { config }
    }
    
    /// 执行带重试的操作
    pub async fn execute<T, F, Fut>(&self, operation: F) -> ResilienceResult<T>
    where
        F: Fn() -> Fut + Send + Sync,
        Fut: std::future::Future<Output = ResilienceResult<T>> + Send,
        T: Send,
    {
        let mut last_error = None;
        
        for attempt in 0..self.config.max_attempts {
            match operation().await {
                Ok(result) => {
                    if attempt > 0 {
                        tracing::info!("操作在第 {} 次尝试时成功", attempt + 1);
                    }
                    return Ok(result);
                }
                Err(error) => {
                    last_error = Some(error.clone());
                    
                    // 如果是最后一次尝试，直接返回错误
                    if attempt + 1 >= self.config.max_attempts {
                        break;
                    }
                    
                    // 检查错误是否可重试
                    if !self.should_retry_error(&error) {
                        tracing::debug!("错误不可重试: {}", error);
                        return Err(error);
                    }
                    
                    // 计算延迟时间
                    let delay = self.calculate_delay(attempt);
                    tracing::debug!(
                        "第 {} 次尝试失败，{:?} 后重试: {}",
                        attempt + 1,
                        delay,
                        error
                    );
                    
                    tokio::time::sleep(delay).await;
                }
            }
        }
        
        if let Some(error) = last_error {
            Err(crate::ResilienceError::retry_error(format!(
                "重试 {} 次后仍然失败: {}",
                self.config.max_attempts,
                error
            )))
        } else {
            Err(crate::ResilienceError::internal_error("重试失败"))
        }
    }
    
    /// 计算延迟时间
    fn calculate_delay(&self, attempt: u32) -> Duration {
        let base_delay = match &self.config.backoff_strategy {
            BackoffStrategy::Fixed { delay } => *delay,
            BackoffStrategy::Linear { initial_delay, increment } => {
                *initial_delay + *increment * attempt
            }
            BackoffStrategy::Exponential { initial_delay, max_delay, multiplier } => {
                let delay_ms = initial_delay.as_millis() as f64 * multiplier.powi(attempt as i32);
                let delay = Duration::from_millis(delay_ms as u64);
                std::cmp::min(delay, *max_delay)
            }
            BackoffStrategy::Custom { .. } => {
                // 默认指数退避
                let delay_ms = 100.0 * 2.0_f64.powi(attempt as i32);
                Duration::from_millis(delay_ms as u64)
            }
        };
        
        // 应用択动
        if self.config.jitter_enabled {
            let jitter_factor = fastrand::f64() * 0.1; // 10% 択动
            let jitter_ms = base_delay.as_millis() as f64 * jitter_factor;
            base_delay + Duration::from_millis(jitter_ms as u64)
        } else {
            base_delay
        }
    }
    
    /// 判断错误是否可重试
    fn should_retry_error(&self, error: &crate::ResilienceError) -> bool {
        for condition in &self.config.retry_conditions {
            match condition {
                RetryCondition::NetworkError => {
                    if matches!(error, crate::ResilienceError::TimeoutError(_)) {
                        return true;
                    }
                }
                RetryCondition::Timeout => {
                    if matches!(error, crate::ResilienceError::TimeoutError(_)) {
                        return true;
                    }
                }
                RetryCondition::HttpStatusRange(start, end) => {
                    // TODO: 实现 HTTP 状态码检查
                    if format!("{}", error).contains(&format!("{}", start)) {
                        return true;
                    }
                }
                _ => {}
            }
        }
        
        // 默认情况下，对临时性错误进行重试
        matches!(error, 
            crate::ResilienceError::TimeoutError(_) | 
            crate::ResilienceError::InternalError(_)
        )
    }
}

/// 指数退避策略
pub struct ExponentialBackoffStrategy {
    initial_delay: Duration,
    max_delay: Duration,
    multiplier: f64,
    max_attempts: u32,
}

impl ExponentialBackoffStrategy {
    pub fn new(initial_delay: Duration, max_delay: Duration, multiplier: f64) -> Self {
        Self {
            initial_delay,
            max_delay,
            multiplier,
            max_attempts: 3,
        }
    }
    
    pub fn with_max_attempts(mut self, max_attempts: u32) -> Self {
        self.max_attempts = max_attempts;
        self
    }
}

#[async_trait]
impl RetryStrategy for ExponentialBackoffStrategy {
    fn calculate_delay(&self, attempt: u32) -> Duration {
        if attempt == 0 {
            return self.initial_delay;
        }
        
        let delay_ms = self.initial_delay.as_millis() as f64 * self.multiplier.powi(attempt as i32 - 1);
        let delay = Duration::from_millis(delay_ms as u64);
        
        std::cmp::min(delay, self.max_delay)
    }
    
    fn should_retry(&self, attempt: u32, _error: &(dyn std::error::Error + Send + Sync)) -> bool {
        attempt < self.max_attempts
    }
    
    fn max_attempts(&self) -> u32 {
        self.max_attempts
    }
    
    fn reset(&mut self) {
        // 指数退避策略通常不需要重置状态
    }
}

/// 线性退避策略
pub struct LinearBackoffStrategy {
    initial_delay: Duration,
    increment: Duration,
    max_attempts: u32,
}

impl LinearBackoffStrategy {
    pub fn new(initial_delay: Duration, increment: Duration) -> Self {
        Self {
            initial_delay,
            increment,
            max_attempts: 3,
        }
    }
    
    pub fn with_max_attempts(mut self, max_attempts: u32) -> Self {
        self.max_attempts = max_attempts;
        self
    }
}

#[async_trait]
impl RetryStrategy for LinearBackoffStrategy {
    fn calculate_delay(&self, attempt: u32) -> Duration {
        self.initial_delay + self.increment * attempt
    }
    
    fn should_retry(&self, attempt: u32, _error: &(dyn std::error::Error + Send + Sync)) -> bool {
        attempt < self.max_attempts
    }
    
    fn max_attempts(&self) -> u32 {
        self.max_attempts
    }
    
    fn reset(&mut self) {
        // 线性退避策略通常不需要重置状态
    }
}

/// 固定延迟策略
pub struct FixedDelayStrategy {
    delay: Duration,
    max_attempts: u32,
}

impl FixedDelayStrategy {
    pub fn new(delay: Duration) -> Self {
        Self {
            delay,
            max_attempts: 3,
        }
    }
    
    pub fn with_max_attempts(mut self, max_attempts: u32) -> Self {
        self.max_attempts = max_attempts;
        self
    }
}

#[async_trait]
impl RetryStrategy for FixedDelayStrategy {
    fn calculate_delay(&self, _attempt: u32) -> Duration {
        self.delay
    }
    
    fn should_retry(&self, attempt: u32, _error: &(dyn std::error::Error + Send + Sync)) -> bool {
        attempt < self.max_attempts
    }
    
    fn max_attempts(&self) -> u32 {
        self.max_attempts
    }
    
    fn reset(&mut self) {
        // 固定延迟策略不需要重置状态
    }
}

impl Default for RetryConfig {
    fn default() -> Self {
        Self {
            max_attempts: 3,
            backoff_strategy: BackoffStrategy::Exponential {
                initial_delay: Duration::from_millis(1000),
                max_delay: Duration::from_secs(30),
                multiplier: 2.0,
            },
            retry_conditions: vec![
                RetryCondition::NetworkError,
                RetryCondition::Timeout,
                RetryCondition::HttpStatusRange(500, 599),
            ],
            budget_percent: 10.0,
            jitter_enabled: true,
            timeout: Some(Duration::from_secs(60)),
        }
    }
}

/// 重试统计信息
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct RetryStats {
    /// 总重试次数
    pub total_retries: u64,
    /// 成功重试次数
    pub successful_retries: u64,
    /// 失败重试次数
    pub failed_retries: u64,
    /// 平均重试次数
    pub average_attempts: f64,
    /// 最后更新时间
    pub last_updated: chrono::DateTime<chrono::Utc>,
}

impl Default for RetryStats {
    fn default() -> Self {
        Self {
            total_retries: 0,
            successful_retries: 0,
            failed_retries: 0,
            average_attempts: 0.0,
            last_updated: chrono::Utc::now(),
        }
    }
}

#[cfg(test)]
mod tests;

// 用于向后兼容的重新导出
pub use RetryStrategy as RetryStrategyTrait;